/*
	File:	DirectInput.cpp
	Author:	TJ Ashby
	
	Comments:	Listens for input from various devices.
*/
#include "DirectInput.h"

#define SAFE_AQUIRE(p)	if(p) p->Acquire()

DirectInput::DirectInput(void)
{
	pKeyboard = nullptr;
	pMouse = nullptr;
	pJoystic1 = nullptr;
	pJoystic2 = nullptr;
}


DirectInput::~DirectInput(void)
{
}

DirectInput* DirectInput::getInstance()
{
	static DirectInput instance;

	return &instance;
}

void DirectInput::Initialize(HWND hwnd,HINSTANCE hInst,bool bShowCursor)
{
#ifdef _DEBUG
	cout << "Initializing Direct Input...";
#endif
	
	DirectInput8Create(hInst,DIRECTINPUT_VERSION,IID_IDirectInput8,(LPVOID*)(&pDirectInput),nullptr);

	pDirectInput->CreateDevice(GUID_SysKeyboard, &pKeyboard, nullptr);
	pDirectInput->CreateDevice(GUID_SysMouse,&pMouse,nullptr);

	pKeyboard->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
	pMouse->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);

	pKeyboard->SetDataFormat(&c_dfDIKeyboard);
	pMouse->SetDataFormat(&c_dfDIMouse);

#ifdef _DEBUG
	pMouse->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
#else
	if(bShowCursor)
		pMouse->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
	else
		pMouse->SetCooperativeLevel(hwnd,DISCL_EXCLUSIVE | DISCL_FOREGROUND);
#endif

	pKeyboard->Acquire();
	pMouse->Acquire();

	mouseClicked = false;

	for(int i = 0;i < 256;++i)
		keys[i] = 0;

	mouseState = new DIMOUSESTATE;

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

void DirectInput::Shutdown()
{
#ifdef _DEBUG
	cout << "Shutting Down Direct Input...";
#endif
	SAFE_RELEASE(pJoystic1);
	SAFE_RELEASE(pJoystic2);
	SAFE_RELEASE(pMouse);
	SAFE_RELEASE(pKeyboard);
	SAFE_RELEASE(pDirectInput);
	SAFE_DELETE(mouseState);

	pJoystic1 = nullptr;
	pJoystic2 = nullptr;
	pKeyboard = nullptr;
	pMouse	  = nullptr;
	pDirectInput = nullptr;

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

void DirectInput::Update()
{
	pKeyboard->Acquire();
	pMouse->Acquire();

	memcpy(&prevState,mouseState,sizeof(DIMOUSESTATE));
	pMouse->GetDeviceState(sizeof(DIMOUSESTATE),mouseState);
	memcpy(prevKeys,keys,256);
	pKeyboard->GetDeviceState(256,keys);
}

bool DirectInput::KeyPressed( unsigned char Key )
{
	if(keys[Key] & 0x80 && !(prevKeys[Key] & 0x80))
		return true;

	return false;
}

bool DirectInput::KeyDown( unsigned char Key )
{
	if(keys[Key] & 0x80)
		return true;

	return false;
}

unsigned char DirectInput::getKeyDown()
{
	unsigned char m_ucAsciiVals[256];

	//	Get the Current Keyboard State.
	if ( !GetKeyboardState(m_ucAsciiVals) )
		return 0; // Could not GetKeyboardState.

	unsigned short usNum	= 0;
	unsigned int uiVKCode	= 0;

	for(short i = 0;i < 256;++i)
	{
		// if the high bit is on, it is pressed
		if (KeyDown( (unsigned char)i ))
		{
			//	Map the Scan Code from DirectInput to a Virtual Key value...
			uiVKCode = MapVirtualKeyEx(i, 1, keyLayout);
			//	...and translate that Virtual Key into an Ascii Value.
			ToAsciiEx(uiVKCode, i, m_ucAsciiVals, &usNum, 0, keyLayout);
		}
	}

	return (char)usNum;
}

bool DirectInput::KeyUp( unsigned char Key )
{
	if(!(keys[Key] & 0x80))
		return true;

	return false;
}

bool DirectInput::KeyReleased( unsigned char Key )
{
	return false;
}

bool DirectInput::MouseButtonDown( int Button )
{
	if(Button < 3 && mouseState->rgbButtons[Button])
		return true;

	return false;
}

bool DirectInput::MouseButtonUp( int Button )
{
	if(Button < 3 && !mouseState->rgbButtons[Button])
		return true;

	return false;
}

bool DirectInput::MouseButtonClicked( int Button )
{
	if(!mouseClicked)
	{
		mouseClicked = true;

		if(Button < 3 && mouseState->rgbButtons[Button])
			return true;
	}

	if(MouseButtonReleased(Button))
		mouseClicked = false;

	return false;
}

bool DirectInput::MouseButtonReleased( int Button )
{
	if(prevState.rgbButtons[Button] && !mouseState->rgbButtons[Button])
		return true;

	return false;
}

int DirectInput::MouseScroll()
{
	return mouseState->lZ;
}

Vector2 DirectInput::MouseDelta()
{
	return Vector2((float)mouseState->lX,(float)mouseState->lY);
}

bool DirectInput::AnyKeyDown()
{
	for(int i = 0;i < 256;++i)
		if(keys[i] & 0x80)
			return true;

	return false;
}

void DirectInput::Clear()
{
	ZeroMemory(keys,256);
	ZeroMemory(prevKeys,256);
	ZeroMemory(mouseState,sizeof(DIMOUSESTATE));
	ZeroMemory(&prevState,sizeof(MouseState));
}

void DirectInput::ClearMouse()
{
	ZeroMemory(mouseState,sizeof(DIMOUSESTATE));
	ZeroMemory(&prevState,sizeof(MouseState));
}

void DirectInput::ClearKeys()
{
	ZeroMemory(keys,256);
	ZeroMemory(prevKeys,256);
}
